#include <iostream>
#include <vector>
#include <fstream>
#include "portaudio.h"

using namespace std;

#define SAMPLE_RATE       16000
#define FRAMES_PER_BUFFER 512
#define NUM_CHANNELS      1
#define NUM_OUTPUT_DEVICE 3

typedef vector<short> VECTOR_SHORT;
typedef vector<short>::iterator VECTOR_SHORT_ITER;

VECTOR_SHORT        m_vectorSamples;
VECTOR_SHORT_ITER	m_iPlaybackIter;

static int playbackCallback( const void *pInputBuffer, void *pOutputBuffer,
                         	 unsigned long iFramesPerBuffer,
                         	 const PaStreamCallbackTimeInfo* timeInfo,
                         	 PaStreamCallbackFlags statusFlags,
                         	 void *userData )
{
	short*			pData	= (short*) pOutputBuffer;
	unsigned long	iOutput = 0;

    (void) pInputBuffer; /* Prevent unused variable warnings. */
    (void) timeInfo;
    (void) statusFlags;
    (void) userData;

	if (pOutputBuffer == NULL)
	{
		cout << "PlaybackCallback was NULL!" << endl;
		return paComplete;
	}

	// Output samples until we either have satified the caller, or we run out
	while (iOutput < iFramesPerBuffer)
	{
		if (m_iPlaybackIter == m_vectorSamples.end())
		{
			// Fill out buffer with zeros
			while (iOutput < iFramesPerBuffer)
			{
				pData[iOutput] = (short) 0;
				iOutput++;
			}
			return paComplete;
		}

		pData[iOutput] = (short) *m_iPlaybackIter;

		m_iPlaybackIter++;
		iOutput++;
	}

	return paContinue;
}

void readFromFile(const string& strFilename)
{
	fstream fin(strFilename.c_str(),ios::in|ios::binary);
	short iSample;
	while(!fin.eof())
	{
		fin.read((char *)&iSample, sizeof(short));
		m_vectorSamples.push_back(iSample);
	}

	fin.close();
}

int main(int argc, char const *argv[])
{
	/* code */
	PaError err = paNoError;

	m_iPlaybackIter = m_vectorSamples.begin();

	err = Pa_Initialize();
	if(err != paNoError){
		cout<<"Portaudio Init Error:"<<Pa_GetErrorText(err)<<endl;
	}

	cout<<"********Playback Demo********"<<endl;
	cout<<"*****************************"<<endl;

	PaStream*           stream;
	PaStreamParameters  outputParameters;

	outputParameters.device                    = NUM_OUTPUT_DEVICE;
	outputParameters.channelCount              = NUM_CHANNELS;
	outputParameters.sampleFormat              = paInt16;
	outputParameters.suggestedLatency          = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
	outputParameters.hostApiSpecificStreamInfo = NULL;

	err = Pa_OpenStream(
            &stream,
            NULL,
            &outputParameters,
            SAMPLE_RATE,
            FRAMES_PER_BUFFER,
            paClipOff,
            playbackCallback,
            NULL);
	if(err != paNoError){
		cout<<"Portaudio OpenStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	cout<<"Reading file to buffer"<<endl;
	readFromFile("recorded.raw");

	cout<<"Press Enter to playback"<<endl;
	char chWait;
	cin.get(chWait);

	err = Pa_StartStream(stream);
	if(err != paNoError){
		cout<<"Portaudio StartStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	while((err = Pa_IsStreamActive(stream)) == 1)
	{
		Pa_Sleep(100);
	}
	if(err < 0){
		cout<<"Active detect error"<<endl;
	}

	err = Pa_StopStream(stream); 
	if(err != paNoError){
		cout<<"Portaudio StopStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	err = Pa_CloseStream(stream);
	if(err != paNoError){
		cout<<"Portaudio CloseStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	err = Pa_Terminate();
	if(err != paNoError){
		cout<<"Portaudio Terminate Error:"<<Pa_GetErrorText(err)<<endl;
	}

	return 0;
}